package com.google.code.jtasks.bugzilla;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import com.google.code.jtasks.bugzilla.proxy.ProcessingUtils;
import com.google.code.jtasks.bugzilla.proxy.bug.BugSearchProxy.FieldIncludeFilters;
import com.google.code.jtasks.model.TaskPropertyValue;
import com.google.code.jtasks.model.TaskId;
import com.google.code.jtasks.model.IMappedTask.TaskField;
import com.google.code.jtasks.util.BadCodeMonkeyException;

/**
 * Enumerates the top-level fields in Bugzilla bugs, mapping them to {@link TaskField}s.
 */
public enum BugField
{
	ID(TaskField.ID)
	{
		/**
		 * @see com.google.code.jtasks.bugzilla.BugField#translate(java.util.Set,
		 *      com.google.code.jtasks.bugzilla.proxy.bug.BugSearchProxy.FieldIncludeFilters)
		 */
		@Override
		public void translate(Set<TaskPropertyValue<?>> allowedValues, FieldIncludeFilters fieldIncludeFilters)
		{
			fieldIncludeFilters.filterByIds(convertToIntegers(allowedValues));
		}
	};

	private final TaskField taskField;

	/**
	 * Constructor. Private, as it can only be used by {@link BugField}'s enum values.
	 * 
	 * @param taskField
	 *            the {@link TaskField} that corresponds to this {@link BugField}
	 */
	private BugField(TaskField taskField)
	{
		this.taskField = taskField;
	}

	/**
	 * Returns the {@link BugField} that corresponds to the specified {@link TaskField}.
	 * 
	 * @param taskField
	 *            the {@link TaskField} to find the corresponding {@link BugField} for
	 * @return the {@link BugField} that corresponds to the specified {@link TaskField}
	 */
	public static BugField findTaskField(TaskField taskField)
	{
		for (BugField bugField : BugField.values())
			if (bugField.taskField == taskField)
				return bugField;

		throw new BadCodeMonkeyException("Unhandled TaskField: " + taskField);
	}

	/**
	 * Translates the specified {@link TaskPropertyValue}s into the corresponding {@link FieldIncludeFilters}
	 * settings.
	 * 
	 * @param allowedValues
	 *            the {@link TaskPropertyValue}s to translate
	 * @param fieldIncludeFilters
	 *            the target {@link FieldIncludeFilters}
	 */
	public abstract void translate(Set<TaskPropertyValue<?>> allowedValues,
			FieldIncludeFilters fieldIncludeFilters);

	/**
	 * Converts the {@link TaskPropertyValue}s to {@link Integer}s.
	 * 
	 * @param taskFieldValues
	 *            the {@link TaskPropertyValue}s to convert
	 * @return {@link Integer} representations of the specified {@link TaskPropertyValue}s
	 */
	private static Collection<Integer> convertToIntegers(Collection<TaskPropertyValue<?>> taskFieldValues)
	{
		Collection<Integer> convertedValues = new HashSet<Integer>();
		for (TaskPropertyValue<?> taskFieldValue : taskFieldValues)
		{
			Object originalValue = taskFieldValue.getValue();
			if (originalValue instanceof Integer)
				convertedValues.add((Integer) originalValue);
			else if (originalValue instanceof TaskId)
				convertedValues.add(convertToInteger((TaskId) originalValue));
			else
				throw new IllegalArgumentException("TaskFieldValue contains missing or incompatible object: "
						+ originalValue);
		}
		return convertedValues;
	}

	/**
	 * Converts the specified {@link TaskId} to an {@link Integer}. Please note that this will only work with
	 * Bugzilla {@link TaskId}s, which are always integers.
	 * 
	 * @param bugzillaTaskId
	 *            the Bugzilla {@link TaskId} to convert
	 * @return an {@link Integer} representation of the specified {@link TaskId}
	 */
	private static Integer convertToInteger(TaskId bugzillaTaskId)
	{
		String idString = bugzillaTaskId.getIdString();
		if (!ProcessingUtils.PATTERN_INTEGER.matcher(idString).matches())
			throw new IllegalArgumentException("Unexpected Bugzilla ID string format: " + idString);

		return Integer.parseInt(idString);
	}
}
